package filter

import (
	"bindolabs/bindo-smart-pos-api/tools/mylog"
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// Filter represents a filter object
type (
	Filter struct {
		Conditions    map[string]interface{}
		AllowedFields []string
		ctx           *gin.Context
	}
)

const AllowedFields = "X-Allowed-Filter-Fields"

// NewFilter creates a new Filter instance
func NewFilter(ctx *gin.Context, fields []string) *Filter {
	f := &Filter{Conditions: make(map[string]interface{})}
	f.ctx = ctx
	f.AllowedFields = fields
	f.parse()

	// 设置返回的请求头
	ctx.Header(AllowedFields, strings.Join(f.AllowedFields, ","))

	return f
}

var OpMap = map[string]string{
	"eq":           " = ?",
	"neq":          " <> ?",
	"contains":     " LIKE ?",
	"not_contains": " NOT LIKE ?",
	"is_null":      " IS NULL",
	"is_not_null":  " IS NOT NULL",
	"gt":           " > ?",
	"gte":          " >= ?",
	"lt":           " < ?",
	"lte":          " <= ?",
}

func encode(i int, field string) string {
	return fmt.Sprintf("%v_%v", i, field)
}

func decode(field string) (int, string) {
	var i int
	fmt.Sscanf(field, "%v_", &i)
	prefix := fmt.Sprintf("%v_", i)
	f := strings.ReplaceAll(field, prefix, "")
	return i, f
}

// parse parses the query parameters into filter conditions
func (f *Filter) parse() *Filter {
	values := f.ctx.Request.URL.Query()
	for index, value := range values {
		// 枚举所有的index
		for _, field := range f.AllowedFields {
			for op := range OpMap {
				_index := fmt.Sprintf("filter[%v][%v]", field, op)
				if index == _index {
					for i, v := range value { // 可能同一个条件使用了两次。比如filter[name][eq]=10&filter[name][eq]=12
						// 使用关键字标识一下。
						f.addCondition(encode(i, field), op, v)
					}
				}
			}
		}
	}
	return f
}

func (f *Filter) addCondition(field, op, value string) {
	// 根据操作符映射获取对应的 SQL 语句
	if sql, ok := OpMap[op]; ok {
		switch op {
		case "is_null", "is_not_null":
			if value == "true" {
				f.Conditions[field+sql] = nil
			}
		case "contains", "not_contains":
			f.Conditions[field+sql] = "%" + value + "%"
		default:
			f.Conditions[field+sql] = value
		}
	} else {
		mylog.Printf("\nUnsupported operation: %s\n", op)
	}
}

// Apply applies the filter conditions to the GORM DB instance
func (f *Filter) Apply(db *gorm.DB) *gorm.DB {
	for condition, value := range f.Conditions {
		_, c := decode(condition)
		db = db.Where(c, value)
	}
	db = f.applyPagination(db)

	// 使用 count 打印 现在的WHERE 语句
	mylog.Printf("\n conditions:%#v, ", f.Conditions)

	return db
}
